<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  
  <title>Java编程思想笔记七 | 净土</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <meta name="description" content="thinking in java; java编程思想; 枚举类型;">
<meta property="og:type" content="article">
<meta property="og:title" content="Java编程思想笔记七">
<meta property="og:url" content="http://howiefh.github.io/2014/11/06/thinking-in-java-note-7/index.html">
<meta property="og:site_name" content="净土">
<meta property="og:description" content="thinking in java; java编程思想; 枚举类型;">
<meta property="og:updated_time" content="2015-07-19T02:56:05.000Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Java编程思想笔记七">
<meta name="twitter:description" content="thinking in java; java编程思想; 枚举类型;">
  
    <link rel="alternative" href="/atom.xml" title="净土" type="application/atom+xml">
  
  
    <link rel="icon" href="/favicon.ico">
  
  <link href="http://fonts.useso.com/css?family=Source+Code+Pro" rel="stylesheet" type="text/css">
  <link rel="stylesheet" href="/css/style.css" type="text/css">
  
<script type="text/javascript">
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');

ga('create', 'UA-40492061-1', 'auto');
ga('send', 'pageview');

</script>


  
<script>
var _hmt = _hmt || [];
(function() {
  var hm = document.createElement("script");
  hm.src = "//hm.baidu.com/hm.js?56d2899c5e919fbf4a7b00de5d1c31dd";
  var s = document.getElementsByTagName("script")[0]; 
  s.parentNode.insertBefore(hm, s);
})();
</script>


</head>

<body>
  <div id="container">
    <div id="wrap">
      <header id="header">
  <div id="banner"></div>
  <div id="header-outer" class="outer">
    <div id="header-title" class="inner">
      <h1 id="logo-wrap">
        <a href="/" id="logo">净土</a>
      </h1>
      
        <h2 id="subtitle-wrap">
          <a href="/" id="subtitle">乐不在外而在心，心以为乐，则是境皆乐；心以为苦，则无境不苦。</a>
        </h2>
      
    </div>
    <div id="header-inner" class="inner">
      <nav id="main-nav">
        <a id="main-nav-toggle" class="nav-icon"></a>
        
          <a class="main-nav-link" href="/">Home</a>
        
          <a class="main-nav-link" href="/archives">Archives</a>
        
      </nav>
      <nav id="sub-nav">
        
          <a id="nav-github-link" class="nav-icon" href="https://github.com/howiefh" title="Github" target="_blank"></a>
        
        
          <a id="nav-rss-link" class="nav-icon" href="/atom.xml" title="RSS Feed" target="_blank"></a>
        
        <a id="nav-search-btn" class="nav-icon" title="Search"></a>
      </nav>
      <div id="search-form-wrap">
        <form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" results="0" class="search-form-input" placeholder="Search"><button type="submit" class="search-form-submit">&#xF002;</button><input type="hidden" name="sitesearch" value="http://howiefh.github.io"></form>
      </div>
    </div>
  </div>
</header>

      <div class="outer">
        <section id="main"><article id="post-thinking-in-java-note-7" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    
<a href="/2014/11/06/thinking-in-java-note-7/" class="article-date">
  <time datetime="2014-11-06T03:02:46.000Z" itemprop="datePublished">2014-11-06</time>
</a>


    
  <div class="article-category">
    <a class="article-category-link" href="/categories/Java/">Java</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 class="article-title" itemprop="name">
      Java编程思想笔记七
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
		
		<div id="toc" class="toc-article">
			<h2 class="toc-title"><span>Contents</span></h2>
		
			<ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#枚举类型"><span class="toc-number">1.</span> <span class="toc-text">枚举类型</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#基本enum特性"><span class="toc-number">1.1.</span> <span class="toc-text">基本enum特性</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#将静态导入用于enum"><span class="toc-number">1.1.1.</span> <span class="toc-text">将静态导入用于enum</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#向enum中添加新方法"><span class="toc-number">1.2.</span> <span class="toc-text">向enum中添加新方法</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#switch语句中的enum"><span class="toc-number">1.3.</span> <span class="toc-text">switch语句中的enum</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#values()的神秘之处"><span class="toc-number">1.4.</span> <span class="toc-text">values()的神秘之处</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#实现，而非继承"><span class="toc-number">1.5.</span> <span class="toc-text">实现，而非继承</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#随机选取"><span class="toc-number">1.6.</span> <span class="toc-text">随机选取</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#使用接口组织枚举"><span class="toc-number">1.7.</span> <span class="toc-text">使用接口组织枚举</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#使用EnumSet替代标志"><span class="toc-number">1.8.</span> <span class="toc-text">使用EnumSet替代标志</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#使用EnumMap"><span class="toc-number">1.9.</span> <span class="toc-text">使用EnumMap</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#常量相关的方法"><span class="toc-number">1.10.</span> <span class="toc-text">常量相关的方法</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#多路分发"><span class="toc-number">1.11.</span> <span class="toc-text">多路分发</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#注解"><span class="toc-number">2.</span> <span class="toc-text">注解</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#基本语法"><span class="toc-number">2.1.</span> <span class="toc-text">基本语法</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#定义注解"><span class="toc-number">2.1.1.</span> <span class="toc-text">定义注解</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#元注解"><span class="toc-number">2.1.2.</span> <span class="toc-text">元注解</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#编写注解处理器"><span class="toc-number">2.2.</span> <span class="toc-text">编写注解处理器</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#注解元素"><span class="toc-number">2.2.1.</span> <span class="toc-text">注解元素</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#默认值限制"><span class="toc-number">2.2.2.</span> <span class="toc-text">默认值限制</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#生成外部文件"><span class="toc-number">2.2.3.</span> <span class="toc-text">生成外部文件</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#注解不支持继承"><span class="toc-number">2.2.4.</span> <span class="toc-text">注解不支持继承</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#使用apt处理注解"><span class="toc-number">2.3.</span> <span class="toc-text">使用apt处理注解</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#将观察者模式应用于apt"><span class="toc-number">2.4.</span> <span class="toc-text">将观察者模式应用于apt</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#基于注解单元测试"><span class="toc-number">2.5.</span> <span class="toc-text">基于注解单元测试</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#javac处理注解"><span class="toc-number">2.6.</span> <span class="toc-text">javac处理注解</span></a></li></ol></li></ol>
		
		</div>
		
        <h2 id="枚举类型">枚举类型</h2><h3 id="基本enum特性">基本enum特性</h3><ul>
<li>Enum类是枚举的一个封装类，是所有枚举类型的超类，它是一个没有抽象方法的抽象类。Enum类实现了Comparable接口，所以它具有compareTo() 方法。同时它还实现了Serializable接口。</li>
<li>ordinal() : 获取枚举元素声明时的顺序，从0开始计算 </li>
<li>可以使用”==”来比较两个枚举实例相同与否，由于编译器自动实现了equals()和hashCode()两个方法</li>
<li>调用getDeclaringClass()方法，我们就能知道其所属的enum类</li>
<li>name() : 返回enum实例声明时的名字，与使用toString()方法效果相同</li>
<li>valueOf() : Enum中的static方法，根据给定的名字返回相应的enum实例，如果不存在给定实例的名字，将会抛出异常。</li>
<li>values() : 这个方法不是Enum提供的。</li>
</ul>
<a id="more"></a>
<h4 id="将静态导入用于enum">将静态导入用于enum</h4><p>如果使用静态导入不会使你的代码难以理解，那么使用静态导入还是有好处的。</p>
<p>在定义enum的同一个文件中，这种技巧无法使用；在默认包中定义enum，这种技巧也无法使用。</p>
<h3 id="向enum中添加新方法">向enum中添加新方法</h3><p><strong>基本上可以将enum看作一个常规的类，也就是说可以向enum添加方法，甚至可以由main方法</strong>。</p>
<p><strong>如果打算添加自己的方法，那么必须在enum实例的最后添加一个分号，而且必须先定义enum实例，实例之前不能有任何方法，否则报错</strong>。</p>
<p>因为我们只能在enum定义的内部使用其构造器创建enum实例，所以enum构造器声明为private并没有什么影响。</p>
<p>此外我们也可以覆盖enum的方法</p>
<h3 id="switch语句中的enum">switch语句中的enum</h3><p>一般情况下我们必须使用enum类型来修饰一个enum实例（Color.RED），但是case语句中却不必如此。</p>
<h3 id="values()的神秘之处">values()的神秘之处</h3><p>enum类都继承自Enum类，但是Enum类中并没有values()方法。<strong>values()是由编译器添加的static方法。编译器还添加了一个只有一个参数的valueOf()方法，和一个static初始化语句块</strong>。</p>
<p>如果将enum实例向上转型为Enum，那么values()方法就不可访问了。不过，在Class中有一个getEnumConstants()方法，所以即便Enum接口中没有values()方法，我们仍然可以通过Class对象取得所有enum实例。</p>
<h3 id="实现，而非继承">实现，而非继承</h3><p><strong>所有enum都继承了Enum类，所以enum不能再继承其他类，但是可以实现一个或多个接口</strong>。</p>
<h3 id="随机选取">随机选取</h3><p>工具类net.mindview.util.Enums可以实现enum实例的随机选择。</p>
<h3 id="使用接口组织枚举">使用接口组织枚举</h3><p>我们希望从enum继承子类，是由于有时我们希望扩展远enum中的元素，有时是因为我们希望使用子类将一个enum中的元素进行分组。</p>
<p><strong>在一个接口的内部，创建实现该接口的枚举，以此将元素进行分组，可以达到将枚举元素分类组织的目的</strong>。</p>
<figure class="highlight groovy"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Food</span> &#123;</span></span><br><span class="line">  <span class="class"><span class="keyword">enum</span> <span class="title">Appetizer</span> <span class="keyword">implements</span> <span class="title">Food</span> &#123;</span></span><br><span class="line">    SALAD, SOUP, SPRING_ROLLS;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="class"><span class="keyword">enum</span> <span class="title">MainCourse</span> <span class="keyword">implements</span> <span class="title">Food</span> &#123;</span></span><br><span class="line">    LASAGNE, BURRITO, PAD_THAI,</span><br><span class="line">    LENTILS, HUMMOUS, VINDALOO;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="class"><span class="keyword">enum</span> <span class="title">Dessert</span> <span class="keyword">implements</span> <span class="title">Food</span> &#123;</span></span><br><span class="line">    TIRAMISU, GELATO, BLACK_FOREST_CAKE,</span><br><span class="line">    FRUIT, CREME_CARAMEL;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="class"><span class="keyword">enum</span> <span class="title">Coffee</span> <span class="keyword">implements</span> <span class="title">Food</span> &#123;</span></span><br><span class="line">    BLACK_COFFEE, DECAF_COFFEE, ESPRESSO,</span><br><span class="line">    LATTE, CAPPUCCINO, TEA, HERB_TEA;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>如果想创建一个“枚举的枚举”，那么可以创建一个新的enum，然后用其实例包装Food中的每一个enum类。</p>
<figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">public enum Course &#123;</span><br><span class="line">  APPETIZER(Food.Appetizer.class),</span><br><span class="line">  MAINCOURSE(Food.MainCourse.class),</span><br><span class="line">  DESSERT(Food.Dessert.class),</span><br><span class="line">  COFFEE(Food.Coffee.class);</span><br><span class="line">  private Food<span class="comment">[]</span> values;</span><br><span class="line">  private Course(Class&lt;? extends Food&gt; <span class="keyword">kind</span>) &#123;</span><br><span class="line">    values = <span class="keyword">kind</span>.getEnumConstants();</span><br><span class="line">  &#125;</span><br><span class="line">  public Food randomSelection() &#123;</span><br><span class="line">    return Enums.random(values);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>另一种管理枚举的方法</p>
<figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">enum SecurityCategory &#123;</span><br><span class="line">  STOCK(Security.Stock.class), BOND(Security.Bond.class);</span><br><span class="line">  Security<span class="comment">[]</span> values;</span><br><span class="line">  SecurityCategory(Class&lt;? extends Security&gt; <span class="keyword">kind</span>) &#123;</span><br><span class="line">    values = <span class="keyword">kind</span>.getEnumConstants();</span><br><span class="line">  &#125;</span><br><span class="line">  interface Security &#123;</span><br><span class="line">    enum Stock implements Security &#123; SHORT, LONG, MARGIN &#125;</span><br><span class="line">    enum Bond implements Security &#123; MUNICIPAL, JUNK &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  public Security randomSelection() &#123;</span><br><span class="line">    return Enums.random(values);</span><br><span class="line">  &#125;</span><br><span class="line">  public static void main(String<span class="comment">[]</span> args) &#123;</span><br><span class="line">    for(int i = 0; i &lt; 10; i++) &#123;</span><br><span class="line">      SecurityCategory category =</span><br><span class="line">        Enums.random(SecurityCategory.class);</span><br><span class="line">      System.out.println(category + <span class="string">": "</span> +</span><br><span class="line">        category.randomSelection());</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="使用EnumSet替代标志">使用EnumSet替代标志</h3><p>EnumSet（可能）就是将一个long值作为比特向量，所以EnumSet非常快速高效。</p>
<p>allOf(Class<e> elementType) 创建一个包含指定元素类型的所有元素的 EnumSet。<br>clone() 返回set的副本<br>complementOf(EnumSet<e> s) 创建一个其元素类型与指定 EnumSet 相同的 EnumSet，最初包含指定 set 中所不包含的此类型的所有元素。<br>copyOf(Collection<e> c) 创建一个从指定 collection 初始化的枚举 set。<br>copyOf(EnumSet<e> s) 创建一个其元素类型与指定 EnumSet 相同的 EnumSet，最初包含相同的元素（如果有的话）。<br>noneOf(Class<e> elementType) 创建一个具有指定元素类型的空 EnumSet。<br>of() 创建一个最初包含指定元素的EnumSet。有很多个重载版本，接收1到5个参数的，以及可变参数的，表现出EnumSet对性能的注重。<br>range(E from, E to) 创建一个最初包含由两个指定端点所定义范围内的所有元素的EnumSet。 </e></e></e></e></e></p>
<h3 id="使用EnumMap">使用EnumMap</h3><p>EnumMap速度很快，只能讲enum的实例作为键来调用put()方法，其它操作和一般Map差不多。</p>
<p>需要在EnumMap的构造器中指定enum类型。</p>
<p>与EnumSet一样，enum实例定义时的次序决定了其在EnumMap中的顺序。</p>
<p>与常量相关的方法相比，EnumMap有一个优点，那EnumMap允许程序员改变值对象，而常量相关的方法在编译期就固定了。</p>
<h3 id="常量相关的方法">常量相关的方法</h3><p><strong>Java允许enum实例编写方法，从而为每个enum实例赋予各自不同的行为。你需要为enum定义一个或多个abstract方法，然后为每个enum实例实现该抽象方法</strong>。</p>
<p>通过相应的enum实例，我们可以调用其上的方法。这通常也称为表驱动的代码，注意它与命令模式的区别。</p>
<figure class="highlight aspectj"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">enum</span> LikeClasses &#123;</span><br><span class="line">  WINKEN &#123; <span class="function"><span class="keyword">void</span> <span class="title">behavior</span><span class="params">()</span> </span>&#123; print(<span class="string">"Behavior1"</span>); &#125; &#125;,</span><br><span class="line">  BLINKEN &#123; <span class="function"><span class="keyword">void</span> <span class="title">behavior</span><span class="params">()</span> </span>&#123; print(<span class="string">"Behavior2"</span>); &#125; &#125;,</span><br><span class="line">  NOD &#123; <span class="function"><span class="keyword">void</span> <span class="title">behavior</span><span class="params">()</span> </span>&#123; print(<span class="string">"Behavior3"</span>); &#125; &#125;;</span><br><span class="line">  <span class="keyword">abstract</span> <span class="function"><span class="keyword">void</span> <span class="title">behavior</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>enum实例的这种特性，很像是子类的行为。enum元素都是static final的。</p>
<p>除了实现abstract方法外，也可以覆盖常量相关的方法。</p>
<p>使用enum可以实现职责链，状态机。</p>
<h3 id="多路分发">多路分发</h3><p>Java只支持单路分发。也就是说，如果要执行的操作包含了不止一个类型未知的对象时，那么Java的动态绑定机制只能处理其中一个类型。</p>
<p>例如，Number是各种数字的超类，a，b都是Number类对象，执行a.plus(b)时，java的动态绑定机制可以判断调用方法的对象a的确切类型，但是却不知道b的确切类型。</p>
<p><strong>解决问题的办法就是多路分发（在上例中只有两个分发，一般称之为两路分发）。如果想使用两路分发，那么就必须有两个方法调用：第一个方法调用决定第一个未知类型，第二个方法调用决定第二个未知的类型。例如在plus方法中再执行 b.plus(this)</strong></p>
<p>书中举了“石头、剪刀、布”的例子，使用enum、常量相关的方法、EnumMap、二维数组进行多路的分发。</p>
<h2 id="注解">注解</h2><blockquote>
<p>注解：注解把元数据与源代码文件结合起来，使得我们能够以由编译器来测试和验证格式，存储有关程序的额外信息。注解在实际的源代码级别保存所有的信息，而不是某种注释性文字。</p>
</blockquote>
<p>Java SE5内置了三种，定义在java.lang中的注解：</p>
<ol>
<li>@Override，表示当前的方法定义将覆盖超类中的方法。如果你不小心拼写错误，或者方法签名对不上被覆盖的方法，编译器就会发出错误提示。</li>
<li>@Deprecated，如果程序员使用了注解为它的元素，那么编译器会发出警告信息</li>
<li>@SuppressWarnings，关闭不当的编译器警告信息。在Java SE5之前的版本中，也可以使用该注解，不过会被忽略不起作用。</li>
</ol>
<p>每当你创建描述符性质的类或接口时，一旦其中包括了重复性的工作，那就可以考虑使用注解来简化与自动化该过程。</p>
<h3 id="基本语法">基本语法</h3><p>从语法角度看，注解的使用方式几乎和修饰符的使用一样。</p>
<h4 id="定义注解">定义注解</h4><p>包 java.lang.annotation 中包含所有定义自定义注解所需用到的原注解和接口。<strong>如接口 java.lang.annotation.Annotation 是所有注解继承的接口,并且是自动继承，不需要定义时指定，类似于所有类都自动继承Object</strong>。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Target</span>(ElementType.METHOD)</span><br><span class="line"><span class="annotation">@Retention</span>(RetentionPolicy.RUNTIME)</span><br><span class="line"><span class="keyword">public</span> <span class="annotation">@interface</span> UseCase &#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">id</span><span class="params">()</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">description</span><span class="params">()</span> <span class="keyword">default</span> “no description”</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PasswordUtils</span> </span>&#123;</span><br><span class="line">    <span class="annotation">@UseCase</span>(id=<span class="number">47</span>, description=”Password must contain at least one numeric”)</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">validatePassword</span><span class="params">(String password)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> password.matches(“\\w*\\d\\w*”);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>定义注解时会需要一些元注解，@Target定义注解应用的地方；@Retention定义注解应用的级别</strong>。</p>
<p>注解中，一般都会包含一些元素以表示某些值。当分析处理注解时，程序或工具可以利用这些值。注解的元素看起来就像接口的方法，唯一的区别是你可以为其指定默认值。没有元素的注解称为标记注解。</p>
<p>description元素有一个default值，如果在注解某个方法时没有给出description的值，则该注解的处理器就会使用此元素的默认值。</p>
<h4 id="元注解">元注解</h4><p>元注解专职负责注解其他的注解。Java只内置了三种标准注解以及四种元注解。元注解定义如下：</p>
<table>
<thead>
<tr>
<th>接口</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>@Target</td>
<td>定义注解应用的地方。包括：CONSTRUCTOR-构造器声明；FIELD-域声明；LOCAL_VARIABLE-局部变量声明；METHOD-方法声明；PACKAGE-包声明；PARAMETER-参数声明；TYPE-类、接口或enum声明</td>
</tr>
<tr>
<td>@Retention</td>
<td>定义注解应用的级别。包括：SOURCE-注解将被编译器丢弃；CLASS-注解在class文件中可用，但会被VM丢弃；RUNTIME-VM将在运行期也保留注解，因此可通过反射机制读取注解信息</td>
</tr>
<tr>
<td>@Documented</td>
<td>将此注解包含在JavaDoc中</td>
</tr>
<tr>
<td>@Inherited</td>
<td>允许子类继承父类中的注解</td>
</tr>
</tbody>
</table>
<h3 id="编写注解处理器">编写注解处理器</h3><p>使用注解的过程中，重要的部分是创建与使用注解处理器。Java SE5扩展了反射机制API，以帮助构造该类工具；同时，提供外部工具apt帮助解析带有注解的Java代码。<br><figure class="highlight gradle"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> UseCaseTracker &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> trackUseCases(List&lt;Integer&gt; useCases, <span class="keyword">Class</span>&lt;?&gt; cl) &#123;</span><br><span class="line">        <span class="keyword">for</span> (Method m : cl.getDeclaredMethods()) &#123;</span><br><span class="line">            UseCase uc = m.getAnnotation(UseCase.<span class="keyword">class</span>);</span><br><span class="line">            <span class="keyword">if</span> (uc != <span class="keyword">null</span>) &#123;</span><br><span class="line">                System.out.<span class="keyword">println</span>(“Found Use <span class="keyword">Case</span>: ” + uc.id() </span><br><span class="line">                + “ ” + uc.<span class="keyword">description</span>());</span><br><span class="line">                useCases.remove(<span class="keyword">new</span> Integer(uc.id()));</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i : UseCases) &#123;</span><br><span class="line">            System.out.<span class="keyword">println</span>(“Warning: Missing use <span class="keyword">case</span>-” + i);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p><strong>反射方法getDeclaredMethods()与getAnnotation()均属于AnnotationElement接口，Class、Method、Field均实现了该接口。getAnnotation()方法返回指定类型的注解对象。使用反射获取到注解对象之后，类似使用调用方法的方式获取注解的值，如uc.id()等</strong>。</p>
<h4 id="注解元素">注解元素</h4><p><strong>注解元素可用基本类型包括：所有基本类型、String、Class、enum、Annotation以及所有前面这些类型的数组。不允许使用任何包装类型，注解可以嵌套</strong>。</p>
<p><strong>因为注解是由编译器计算而来的，因此，所有元素值必须是编译期常量</strong>。</p>
<p>如果元素值是一个数组，要将它的值用大括号括起来<code>@Test(array={&quot;a&quot;,&quot;b&quot;})</code>，如果只有一个值，也可以省去括号。</p>
<h4 id="默认值限制">默认值限制</h4><p><strong>注解元素不能有不确定的值，也就是说，元素必须要么具有默认值，要么使用注解时提供元素的值</strong>。<br><strong>不能以null作为其值。为了绕开这个约束，可以定义一些特殊的值，例如空字符串或负数，以表示某个元素不存在</strong>。</p>
<h4 id="生成外部文件">生成外部文件</h4><p>部分Framework需要提供额外信息如XML描述文件才能与源代码协同工作，此时同一个类拥有两个单独的信息源，这常导致代码同步问题。但是使用注解，则可将所有信息都保存在JavaBean源文件中。</p>
<p>@Target注解中指定的每一个ElementType就是一个约束，它告诉编译器，这个自定义的注解只能应用于该类型。程序员可以指定enum ElementType中的某个值，或者以逗号分隔的形式指定多个值。如果想要将注解应用于所有ElementType，那么可以省去@Target元注解，不过这并不常见。</p>
<p>注解嵌套：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Target</span>(ElementType.FIELD)</span><br><span class="line"><span class="annotation">@Retention</span>(RetentionPolicy.RUNTIME)</span><br><span class="line"><span class="keyword">public</span> <span class="annotation">@interface</span> Constraints &#123;</span><br><span class="line">    <span class="function"><span class="keyword">boolean</span> <span class="title">primaryKey</span><span class="params">()</span> <span class="keyword">default</span> <span class="keyword">false</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">boolean</span> <span class="title">allowNull</span><span class="params">()</span> <span class="keyword">default</span> <span class="keyword">true</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">boolean</span> <span class="title">unique</span><span class="params">()</span> <span class="keyword">default</span> <span class="keyword">false</span></span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="annotation">@Target</span>(ElementType.FIELD)</span><br><span class="line"><span class="annotation">@Retention</span>(RetentionPolicy.RUNTIME)</span><br><span class="line"><span class="keyword">public</span> <span class="annotation">@interface</span> SQLString &#123;</span><br><span class="line">    <span class="function"><span class="keyword">int</span> <span class="title">value</span><span class="params">()</span> <span class="keyword">default</span> 0</span>;</span><br><span class="line">    <span class="function">String <span class="title">name</span><span class="params">()</span> <span class="keyword">default</span> ""</span>;</span><br><span class="line">    <span class="function">Constraints <span class="title">constraints</span><span class="params">()</span> <span class="keyword">default</span> @<span class="title">Constraints</span><span class="params">(unique=<span class="keyword">true</span>)</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>SQLString中元素constraints的类型就是一个注解。</p>
<p>快捷方式：<br><strong>注解中定义了名为value的元素，且在应用该注解时，若该元素是唯一需赋值元素，则无需使用名-值对语法，只需在括号内给出value值即可</strong>。</p>
<figure class="highlight less"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">pubic</span> <span class="tag">class</span> <span class="tag">Member</span> &#123;</span><br><span class="line">    <span class="variable">@SQLString</span>(<span class="number">30</span>)</span><br><span class="line">    String firstName;</span><br><span class="line">    <span class="variable">@SQLString</span>(value = <span class="number">30</span>, constraints = <span class="variable">@Constraints</span>(primaryKey = true))</span><br><span class="line">    String handler;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>其中<code>@SQLString(30)</code>就是只提供了一个值。</p>
<p><strong>变通之道</strong><br>嵌套注解有时会使代码非常复杂，可以同时使用两个注解类型来注解一个域。</p>
<h4 id="注解不支持继承">注解不支持继承</h4><p><strong>由于注解没有继承机制，所以要获得近似多态的行为，使用getDeclaredAnnotations()是唯一的办法（Field类中提供该方法）</strong>。</p>
<h3 id="使用apt处理注解">使用apt处理注解</h3><blockquote>
<p>apt工具及其关联的API已被javac和标准注释处理API javax.annotation.processing 和 javax.lang.model取代。</p>
</blockquote>
<p>与Javac一样，apt被设计为操作Java源文件，而不是编译后的类；自定义的每个注解都需要自己的处理器，而apt工具能够很容易的将多个注解处理器组合在一起。使用apt时必须指明一个工厂类，或者指明能找到apt所需工厂类的路径，apt需要工厂类来为其指明正确的处理器；使用apt生成注解处理器时，无法利用Java反射机制，因为操作的是源代码。</p>
<p>使用apt，以书中的annotations包为例。<br>首先，确保CLASSPATH变量中有tools.jar包，然后<code>cd TIJ4-code</code>，执行<code>javac annotations\InterfaceExtractorProcessorFactory.java</code>编译完成后，然后执行<code>apt -factory annotations.InterfaceExtractorProcessorFactory annotations\Multiplier.java -s annotations</code></p>
<h3 id="将观察者模式应用于apt">将观察者模式应用于apt</h3><p>mirror API提供了对访问者设计模式的支持。<br>一个访问者会遍历某个数据结构或一个对象的集合，对其中的每一个对象执行一个操作，该数据结构无需有序，而你对每个对象执行的操作，都是特定于此对象的类型。这就是操作与对象解耦，也就是说，你可以添加新的操作，而无需向类的定义中添加方法。</p>
<h3 id="基于注解单元测试">基于注解单元测试</h3><p>单元测试工具：JUnit。作者在书中提供了一个工具类库。</p>
<p>javassist应用于字节码工程。</p>
<h3 id="javac处理注解">javac处理注解</h3><p>Java SE 6 引入了一个新的功能，叫做 可插入注解处理（Pluggable Annotation Processing） 框架，它提供了标准化的支持来编写自定义的注解处理器。之所以称为“可插入”，是因为注解处理器可以动态插入到 javac 中，并可以对出现在 Java 源文件中的一组注解进行操作。此框架具有两个部分：一个用于声明注解处理器并与其交互的 API — 包 javax.annotation.processing — 和一个用于对 Java 编程语言进行建模的 API — 包 javax.lang.model。</p>
<p>下面的例子可以提取出一个类中的public方法，构造成一个新的接口。<br>InterfaceExtractorProcessor.java 文件</p>
<figure class="highlight openscad"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line">package annotations;</span><br><span class="line"></span><br><span class="line"><span class="built_in">import</span> javax.annotation.processing.<span class="built_in">*</span>;</span><br><span class="line"><span class="built_in">import</span> java.io.<span class="built_in">*</span>;</span><br><span class="line"><span class="built_in">import</span> java.util.<span class="built_in">*</span>;</span><br><span class="line"><span class="built_in">import</span> javax.tools.<span class="built_in">*</span>;</span><br><span class="line"><span class="built_in">import</span> javax.lang.model.<span class="built_in">*</span>;</span><br><span class="line"><span class="built_in">import</span> javax.lang.model.util.<span class="built_in">*</span>;</span><br><span class="line"><span class="built_in">import</span> javax.lang.model.element.<span class="built_in">*</span>;</span><br><span class="line"></span><br><span class="line">@SupportedAnnotationTypes<span class="params">(<span class="string">"annotations.ExtractInterface"</span>)</span></span><br><span class="line">@SupportedSourceVersion<span class="params">(SourceVersion.RELEASE_8)</span></span><br><span class="line">public class InterfaceExtractorProcessor extends AbstractProcessor &#123;</span><br><span class="line">    @Override</span><br><span class="line">    public boolean process<span class="params">(Set&lt;? extends TypeElement&gt; annotations, RoundEnvironment roundEnv)</span> &#123;</span><br><span class="line">        <span class="keyword">for</span> <span class="params">(Element e : roundEnv.getElementsAnnotatedWith<span class="params">(ExtractInterface.class)</span>)</span> &#123;</span><br><span class="line">            Set&lt;ExecutableElement&gt; interfaceMethods = new HashSet&lt;&gt;<span class="params">()</span>;</span><br><span class="line">            ExtractInterface annot = e.getAnnotation<span class="params">(ExtractInterface.class)</span>;</span><br><span class="line">            <span class="keyword">for</span><span class="params">(ExecutableElement m : ElementFilter.methodsIn<span class="params">(e.getEnclosedElements<span class="params">()</span>)</span>)</span> &#123;</span><br><span class="line">                <span class="keyword">if</span><span class="params">(m.getModifiers<span class="params">()</span>.contains<span class="params">(Modifier.PUBLIC)</span> &amp;&amp;</span><br><span class="line">                        !<span class="params">(m.getModifiers<span class="params">()</span>.contains<span class="params">(Modifier.STATIC)</span>)</span></span><br><span class="line">                        )</span></span><br><span class="line">                    interfaceMethods.add<span class="params">(m)</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span><span class="params">(interfaceMethods.size<span class="params">()</span> &gt; <span class="number">0</span>)</span> &#123;</span><br><span class="line">                try &#123;</span><br><span class="line">                    JavaFileObject sourceFile = processingEnv.getFiler<span class="params">()</span>.createSourceFile<span class="params">(</span><br><span class="line">                            annot.value<span class="params">()</span>)</span>;</span><br><span class="line">                    PrintWriter writer = new PrintWriter<span class="params">(sourceFile.openWriter<span class="params">()</span>)</span>;</span><br><span class="line">                    writer.println<span class="params">(<span class="string">"package "</span> +</span><br><span class="line">                            processingEnv.getElementUtils<span class="params">()</span>.getPackageOf<span class="params">(e)</span>.getQualifiedName<span class="params">()</span> +<span class="string">";"</span>)</span>;</span><br><span class="line">                    writer.println<span class="params">(<span class="string">"public interface "</span> +</span><br><span class="line">                            annot.value<span class="params">()</span> + <span class="string">" &#123;"</span>)</span>;</span><br><span class="line"></span><br><span class="line">                    <span class="keyword">for</span><span class="params">(ExecutableElement m : interfaceMethods)</span> &#123;</span><br><span class="line">                        writer.print<span class="params">(<span class="string">"  public "</span>)</span>;</span><br><span class="line">                        writer.print<span class="params">(m.getReturnType<span class="params">()</span> + <span class="string">" "</span>)</span>;</span><br><span class="line">                        writer.print<span class="params">(m.getSimpleName<span class="params">()</span> + <span class="string">" ("</span>)</span>;</span><br><span class="line">                        int i = <span class="number">0</span>;</span><br><span class="line">                        </span><br><span class="line">                        <span class="keyword">for</span><span class="params">(VariableElement parm : m.getParameters<span class="params">()</span>)</span> &#123;</span><br><span class="line">                            writer.print<span class="params">(parm.asType<span class="params">()</span> + <span class="string">" "</span> +</span><br><span class="line">                                    parm.getSimpleName<span class="params">()</span>)</span>;</span><br><span class="line">                            <span class="keyword">if</span><span class="params">(++i &lt; m.getParameters<span class="params">()</span>.size<span class="params">()</span>)</span></span><br><span class="line">                                writer.print<span class="params">(<span class="string">", "</span>)</span>;</span><br><span class="line">                        &#125;</span><br><span class="line">                        writer.println<span class="params">(<span class="string">");"</span>)</span>;</span><br><span class="line">                    &#125;</span><br><span class="line">                    writer.println<span class="params">(<span class="string">"&#125;"</span>)</span>;</span><br><span class="line">                    writer.close<span class="params">()</span>;</span><br><span class="line">                &#125; catch<span class="params">(IOException ioe)</span> &#123;</span><br><span class="line">                    throw new RuntimeException<span class="params">(ioe)</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; </span><br><span class="line">        return <span class="literal">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125; <span class="comment">///:~</span></span><br></pre></td></tr></table></figure>
<p>ExtractInterface.java文件</p>
<figure class="highlight aspectj"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> annotations;</span><br><span class="line"><span class="keyword">import</span> java.lang.annotation.*;</span><br><span class="line"></span><br><span class="line"><span class="annotation">@Target</span>(ElementType.TYPE)</span><br><span class="line"><span class="annotation">@Retention</span>(RetentionPolicy.SOURCE)</span><br><span class="line"><span class="keyword">public</span> <span class="annotation">@interface</span> ExtractInterface &#123;</span><br><span class="line">  <span class="keyword">public</span> <span class="function">String <span class="title">value</span><span class="params">()</span></span>;</span><br><span class="line">&#125; <span class="comment">///:~</span></span><br></pre></td></tr></table></figure>
<p>Multiplier.java文件</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> annotations;</span><br><span class="line"><span class="annotation">@ExtractInterface</span>(<span class="string">"IMultiplier"</span>)</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Multiplier</span> </span>&#123;</span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">multiply</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> y)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">int</span> total = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">for</span>(<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; x; i++)</span><br><span class="line">      total = add(total, y);</span><br><span class="line">    <span class="keyword">return</span> total;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="function"><span class="keyword">private</span> <span class="keyword">int</span> <span class="title">add</span><span class="params">(<span class="keyword">int</span> x, <span class="keyword">int</span> y)</span> </span>&#123; <span class="keyword">return</span> x + y; &#125;</span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">    Multiplier m = <span class="keyword">new</span> Multiplier();</span><br><span class="line">    System.out.println(<span class="string">"11*16 = "</span> + m.multiply(<span class="number">11</span>, <span class="number">16</span>));</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>自定义注解处理器继承 AbstractProcessor（这是 Processor 接口的默认实现），并覆盖 process() 方法。</p>
<p>注解处理器类将使用两个类级别的注解 @SupportedAnnotationTypes 和 @SupportedSourceVersion 来装饰。 SupportedSourceVersion 注解指定注解处理器支持的最新的源版本。SupportedAnnotationTypes 注解指示此特定的注解处理器对哪些注解感兴趣。例如，如果处理器只需处理 Java Persistence API (JPA) 注解，则将使用 @SupportedAnnotationTypes (“javax.persistence.<em>“)。值得注意的一点是，如果将支持的注解类型指定为 @SupportedAnnotationTypes(“</em>“)，即使没有任何注解，仍然会调用注解处理器。这允许我们有效利用建模 API 以及 Tree API 来执行通用的源码处理。使用这些 API，可以获得与修改符、字段、方法等有关的大量有用的信息。</p>
<p>是否调用注解处理器取决于源码中存在哪些注解，哪些处理器配置为可用，哪些注解类型是可用的后处理器进程。注解处理可能发生在多个轮回中。例如，在第一个轮回中，将处理原始输入 Java 源文件；在第二个轮回中，将考虑处理由第一个轮回生成的文件，等等。自定义处理器应覆盖 AbstractProcessor 的 process()。此方法接受两个参数：</p>
<ul>
<li>源文件中找到的一组 TypeElements/ 注解。</li>
<li>封装有关注解处理器当前处理轮回的信息的 RoundEnvironment。</li>
</ul>
<p>如果处理器声明其支持的注解类型，则 process() 方法返回 true，而不会为这些注解调用其他处理器。否则，process() 方法返回 false 值，并将调用下一个可用的处理器（如果存在的话）。</p>
<p>我们使用下面的调用来创建源文件。</p>
<figure class="highlight ocaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">JavaFileObject</span> sourceFile = processingEnv.getFiler<span class="literal">()</span>.createSourceFile(annot.<span class="keyword">value</span><span class="literal">()</span>);</span><br><span class="line"><span class="type">PrintWriter</span> writer = <span class="keyword">new</span> <span class="type">PrintWriter</span>(sourceFile.openWriter<span class="literal">()</span>);</span><br></pre></td></tr></table></figure>
<p>Java SE 6 的 javac 实用程序提供一个称为 -processor 的选项，来接受要插入到的注解处理器的完全限定名。</p>
<figure class="highlight gcode"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">javac -processor ProcessorClass<span class="label">Name1</span>,ProcessorClass<span class="label">Name2</span>,...  sourceFiles</span><br></pre></td></tr></table></figure>
<p>先编译注解处理器<br><figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="title">javac</span> annotations/InterfaceExtractorProcessor.java</span><br></pre></td></tr></table></figure></p>
<p>然后运行<br><figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">javac -processor annotations<span class="class">.InterfaceExtractorProcessor</span> annotations/Multiplier.java</span><br></pre></td></tr></table></figure></p>
<p>接口文件IMultiplier.java已经在当前路径下生成。</p>

      
    </div>
    <footer class="article-footer">
	  
	  <!-- 百度分享 Start -->
	  <div class="bdsharebuttonbox"><a href="#" class="bds_more" data-cmd="more"></a><a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间"></a><a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博"></a><a href="#" class="bds_tqq" data-cmd="tqq" title="分享到腾讯微博"></a><a href="#" class="bds_renren" data-cmd="renren" title="分享到人人网"></a><a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信"></a></div>
	  <!-- 百度分享 End -->
	  
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/Thinking-in-Java/">Thinking in Java</a></li></ul>

	  
<span>
Updated:<time datetime="2015-07-19T02:56:05.000Z" itemprop="dateModified">2015-07-19</time>
</span>


    </footer>
  </div>
  
    
<nav id="article-nav">
  
    <a href="/2014/12/24/javamail/" id="article-nav-newer" class="article-nav-link-wrap">
      <strong class="article-nav-caption">Newer</strong>
      <div class="article-nav-title">
        
          JavaMail简介
        
      </div>
    </a>
  
  
    <a href="/2014/11/04/thinking-in-java-note-6/" id="article-nav-older" class="article-nav-link-wrap">
      <strong class="article-nav-caption">Older</strong>
      <div class="article-nav-title">Java编程思想笔记六</div>
    </a>
  
</nav>

  
</article>



<!-- 多说评论框 start -->

<section id="comments">
  <div class="ds-thread"  data-thread-key="/2014/11/06/thinking-in-java-note-7/" data-title="Java编程思想笔记七" data-url="http://howiefh.github.io/2014/11/06/thinking-in-java-note-7/" id="ds_thread">
    <noscript>Please enable JavaScript to view the <a href="//duoshuo.com/?ref_noscript">comments powered by duoshuo.</a></noscript>
  </div>
</section>

<!-- 多说评论框 end -->
</section>
        
          
  <div id="toc" class="toc-aside">
  <h2 class="toc-title">Contents</h2>
    
        <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#枚举类型"><span class="toc-number">1.</span> <span class="toc-text">枚举类型</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#基本enum特性"><span class="toc-number">1.1.</span> <span class="toc-text">基本enum特性</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#将静态导入用于enum"><span class="toc-number">1.1.1.</span> <span class="toc-text">将静态导入用于enum</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#向enum中添加新方法"><span class="toc-number">1.2.</span> <span class="toc-text">向enum中添加新方法</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#switch语句中的enum"><span class="toc-number">1.3.</span> <span class="toc-text">switch语句中的enum</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#values()的神秘之处"><span class="toc-number">1.4.</span> <span class="toc-text">values()的神秘之处</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#实现，而非继承"><span class="toc-number">1.5.</span> <span class="toc-text">实现，而非继承</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#随机选取"><span class="toc-number">1.6.</span> <span class="toc-text">随机选取</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#使用接口组织枚举"><span class="toc-number">1.7.</span> <span class="toc-text">使用接口组织枚举</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#使用EnumSet替代标志"><span class="toc-number">1.8.</span> <span class="toc-text">使用EnumSet替代标志</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#使用EnumMap"><span class="toc-number">1.9.</span> <span class="toc-text">使用EnumMap</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#常量相关的方法"><span class="toc-number">1.10.</span> <span class="toc-text">常量相关的方法</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#多路分发"><span class="toc-number">1.11.</span> <span class="toc-text">多路分发</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#注解"><span class="toc-number">2.</span> <span class="toc-text">注解</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#基本语法"><span class="toc-number">2.1.</span> <span class="toc-text">基本语法</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#定义注解"><span class="toc-number">2.1.1.</span> <span class="toc-text">定义注解</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#元注解"><span class="toc-number">2.1.2.</span> <span class="toc-text">元注解</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#编写注解处理器"><span class="toc-number">2.2.</span> <span class="toc-text">编写注解处理器</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#注解元素"><span class="toc-number">2.2.1.</span> <span class="toc-text">注解元素</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#默认值限制"><span class="toc-number">2.2.2.</span> <span class="toc-text">默认值限制</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#生成外部文件"><span class="toc-number">2.2.3.</span> <span class="toc-text">生成外部文件</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#注解不支持继承"><span class="toc-number">2.2.4.</span> <span class="toc-text">注解不支持继承</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#使用apt处理注解"><span class="toc-number">2.3.</span> <span class="toc-text">使用apt处理注解</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#将观察者模式应用于apt"><span class="toc-number">2.4.</span> <span class="toc-text">将观察者模式应用于apt</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#基于注解单元测试"><span class="toc-number">2.5.</span> <span class="toc-text">基于注解单元测试</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#javac处理注解"><span class="toc-number">2.6.</span> <span class="toc-text">javac处理注解</span></a></li></ol></li></ol>
    
  </div>

<aside id="sidebar">

  
    
<div class="widget-wrap">
  <h3 class="widget-title">ABOUT ME</h3>
  <ul class="widget about-me">
    
    <li><img class="author" title="About me" src="http://fh-1.qiniudn.com/okal-eltocat.jpg" /></li>
    
    
    <li>Hi,I'm FengHao.</li>
    
    <li>I'll share something interesting and my learning experience with you at this blog.</li>
    
    <li>前博客:<a href="http://hi.baidu.com/idea_star" target="_BLANK">百度空间</a></li>
    
  </ul>
</div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Categories</h3>
    <div class="widget">
      <ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/Android/">Android</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/C/">C</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Database/">Database</a><span class="category-list-count">13</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/Database/MongoDB/">MongoDB</a><span class="category-list-count">10</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Database/MySQL/">MySQL</a><span class="category-list-count">2</span></li></ul></li><li class="category-list-item"><a class="category-list-link" href="/categories/Eclipse/">Eclipse</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/FTP/">FTP</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Git/">Git</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Hexo/">Hexo</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Java/">Java</a><span class="category-list-count">20</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/Java/FreeMarker/">FreeMarker</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Java/Shiro/">Shiro</a><span class="category-list-count">2</span></li></ul></li><li class="category-list-item"><a class="category-list-link" href="/categories/JavaEE/">JavaEE</a><span class="category-list-count">4</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/JavaEE/Hibernate/">Hibernate</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/JavaEE/JSP/">JSP</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/JavaEE/Spring/">Spring</a><span class="category-list-count">2</span></li></ul></li><li class="category-list-item"><a class="category-list-link" href="/categories/JavaScript/">JavaScript</a><span class="category-list-count">5</span><ul class="category-list-child"><li class="category-list-item"><a class="category-list-link" href="/categories/JavaScript/jQuery/">jQuery</a><span class="category-list-count">1</span></li></ul></li><li class="category-list-item"><a class="category-list-link" href="/categories/Linux/">Linux</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/PHP/">PHP</a><span class="category-list-count">5</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Suse/">Suse</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Ubuntu/">Ubuntu</a><span class="category-list-count">5</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/Vim/">Vim</a><span class="category-list-count">8</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/编程/">编程</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/软件/">软件</a><span class="category-list-count">1</span></li></ul>
    </div>
  </div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Tag Cloud</h3>
    <div class="widget tagcloud">
      <a href="/tags/Android/" style="font-size: 14.75px; color: #65bfa7">Android</a> <a href="/tags/C/" style="font-size: 13.88px; color: #71c1c2">C</a> <a href="/tags/CAS/" style="font-size: 13px; color: #7dc3de">CAS</a> <a href="/tags/Chrome/" style="font-size: 13px; color: #7dc3de">Chrome</a> <a href="/tags/Clean-Code/" style="font-size: 13.88px; color: #71c1c2">Clean Code</a> <a href="/tags/Database/" style="font-size: 13px; color: #7dc3de">Database</a> <a href="/tags/Eclipse/" style="font-size: 13px; color: #7dc3de">Eclipse</a> <a href="/tags/FTP/" style="font-size: 13.88px; color: #71c1c2">FTP</a> <a href="/tags/FreeMarker/" style="font-size: 14.75px; color: #65bfa7">FreeMarker</a> <a href="/tags/Gcc/" style="font-size: 13px; color: #7dc3de">Gcc</a> <a href="/tags/Git/" style="font-size: 14.75px; color: #65bfa7">Git</a> <a href="/tags/Github-Pages/" style="font-size: 13px; color: #7dc3de">Github Pages</a> <a href="/tags/Hexo/" style="font-size: 14.75px; color: #65bfa7">Hexo</a> <a href="/tags/Hibernate/" style="font-size: 13px; color: #7dc3de">Hibernate</a> <a href="/tags/JSP/" style="font-size: 13px; color: #7dc3de">JSP</a> <a href="/tags/JVM/" style="font-size: 14.75px; color: #65bfa7">JVM</a> <a href="/tags/Java/" style="font-size: 14.75px; color: #65bfa7">Java</a> <a href="/tags/JavaMail/" style="font-size: 13px; color: #7dc3de">JavaMail</a> <a href="/tags/JavaScript/" style="font-size: 16.5px; color: #4dbc6f">JavaScript</a> <a href="/tags/Linux/" style="font-size: 13.88px; color: #71c1c2">Linux</a> <a href="/tags/Log/" style="font-size: 13px; color: #7dc3de">Log</a> <a href="/tags/Markdown/" style="font-size: 13.88px; color: #71c1c2">Markdown</a> <a href="/tags/MongoDB/" style="font-size: 20px; color: #1db400">MongoDB</a> <a href="/tags/MySQL/" style="font-size: 13.88px; color: #71c1c2">MySQL</a> <a href="/tags/PHP/" style="font-size: 16.5px; color: #4dbc6f">PHP</a> <a href="/tags/Rhythmbox/" style="font-size: 13px; color: #7dc3de">Rhythmbox</a> <a href="/tags/SSO/" style="font-size: 13px; color: #7dc3de">SSO</a> <a href="/tags/Servlet/" style="font-size: 13px; color: #7dc3de">Servlet</a> <a href="/tags/Shiro/" style="font-size: 13.88px; color: #71c1c2">Shiro</a> <a href="/tags/Spring/" style="font-size: 13.88px; color: #71c1c2">Spring</a> <a href="/tags/Suse/" style="font-size: 13px; color: #7dc3de">Suse</a> <a href="/tags/Thinking-in-Java/" style="font-size: 19.13px; color: #29b61c">Thinking in Java</a> <a href="/tags/Ubuntu/" style="font-size: 17.38px; color: #41ba53">Ubuntu</a> <a href="/tags/Vim/" style="font-size: 18.25px; color: #35b838">Vim</a> <a href="/tags/VirtualBox/" style="font-size: 13px; color: #7dc3de">VirtualBox</a> <a href="/tags/Vsftpd/" style="font-size: 13px; color: #7dc3de">Vsftpd</a> <a href="/tags/jQuery/" style="font-size: 13px; color: #7dc3de">jQuery</a> <a href="/tags/pam-mysql/" style="font-size: 13px; color: #7dc3de">pam_mysql</a> <a href="/tags/小米/" style="font-size: 13px; color: #7dc3de">小米</a> <a href="/tags/软件/" style="font-size: 15.63px; color: #59bd8b">软件</a>
    </div>
  </div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Archives</h3>
    <div class="widget">
      <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/09/">September 2015</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/08/">August 2015</a><span class="archive-list-count">4</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/07/">July 2015</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/05/">May 2015</a><span class="archive-list-count">5</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/04/">April 2015</a><span class="archive-list-count">4</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/03/">March 2015</a><span class="archive-list-count">4</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/02/">February 2015</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/12/">December 2014</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/11/">November 2014</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/10/">October 2014</a><span class="archive-list-count">4</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/09/">September 2014</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/08/">August 2014</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/07/">July 2014</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/06/">June 2014</a><span class="archive-list-count">6</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/05/">May 2014</a><span class="archive-list-count">4</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/04/">April 2014</a><span class="archive-list-count">4</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/03/">March 2014</a><span class="archive-list-count">3</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/02/">February 2014</a><span class="archive-list-count">11</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2014/01/">January 2014</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/12/">December 2013</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/11/">November 2013</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/08/">August 2013</a><span class="archive-list-count">3</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/07/">July 2013</a><span class="archive-list-count">2</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/06/">June 2013</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/05/">May 2013</a><span class="archive-list-count">5</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2013/04/">April 2013</a><span class="archive-list-count">3</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2012/03/">March 2012</a><span class="archive-list-count">1</span></li></ul>
    </div>
  </div>


  
    <div class="widget-wrap">
  <h3 class="widget-title">Calendar</h3>
  <div class="widget">
    <div id="g-calendar" class="g-calendar">
        <span class="g-calendar-prev"></span>
		 
        <span class="g-calendar-back"></span>
        <span class="g-calendar-now"></span>
		 
        <span class="g-calendar-next"></span>
        <div class="g-calendar-hd"></div>
        <div class="g-calendar-tit"></div>
        <div class="g-calendar-bd"></div>
    </div>
  </div>
</div>
<script type="text/javascript">
function LGY_calendar(wrapId, options){
    this.oWrap = this.getId(wrapId);
    this.oHead = this.getByClassName('g-calendar-hd',this.oWrap)[0];
    this.oBody = this.getByClassName('g-calendar-bd',this.oWrap)[0];
    this.oTit = this.getByClassName('g-calendar-tit',this.oWrap)[0];
    this.oPrev = this.getByClassName('g-calendar-prev',this.oWrap)[0];
    this.oNext = this.getByClassName('g-calendar-next',this.oWrap)[0];
    this.oNow = this.getByClassName('g-calendar-now',this.oWrap)[0];
    this.oBack = this.getByClassName('g-calendar-back',this.oWrap)[0];
    this.init();
}
LGY_calendar.prototype = {
    ///////////获取ID元素
    getId:function(id){
        return document.getElementById(id);
    },
    ////////获取css类名元素
    getByClassName:function(className,parent){
        var elem = [],
            node = parent != undefined&&parent.nodeType==1?parent.getElementsByTagName('*'):document.getElementsByTagName('*'),
            p = new RegExp("(^|\\s)"+className+"(\\s|$)");
        for(var n=0,i=node.length;n<i;n++){
            if(p.test(node[n].className)){
                elem.push(node[n]);
            }
        }
        return elem;
    },
    //填充日历
    fillDate:function(year,month){
        //本月份第一天是星期几-为显示上个月的天数做铺垫
        var first_day = new Date(year,month,1).getDay(),
        //如果刚好是星期天，则空出一行（显示上个月的天数）
            first_day = first_day == 0?first_day=7:first_day;
        //本月份最后一天是几号
        var final_date = new Date(year,month+1,0).getDate(),
        //上个月的最后一天是几号
            last_date = new Date(year,month,0).getDate(),
        //剩余的格子数--即排在末尾的格子数
            surplus = 42 - first_day - final_date;
        //设置年的链接
        var yearHead = "<a href='/" + "archives/" + year + "/'>" + year + " "+ "</a>"; 
        //设置年的链接
        var monthHead = "";
        var month1 = month + 1;
        if (month1 < 10) {
            monthHead = "<a href='/" + "archives/" + year + "/" + "0" + month1 + "/'>" + " " + month1 + " " + "</a>";
        } else {
            monthHead = "<a href='/" + "archives/" + year + "/" + month1 + "/'>" + " " + month1 + " " + "</a>";
        }
        //设置表头的日历
        this.oHead.innerHTML = yearHead+'年'+monthHead+'月';
        //填充日历执行
        var html = '';
        //上个月的显示天数
        for(var i=0;i<first_day;i++){
            html+='<span class="g-calendar-grey">'+(last_date-(first_day-1)+i)+'</span>';
        }
        //本月的显示天数
        var postdate = new Date("Thu Nov 06 2014 11:02:46 GMT+0800"); 
        if (true && postdate.getFullYear() == year && postdate.getMonth() == month) { 
            html += '<span>1</span><span>2</span><span>3</span><span><a href="/2014/11/04/thinking-in-java-note-6/" title="Java编程思想笔记六">4</a></span><span>5</span><span><a href="/2014/11/06/thinking-in-java-note-7/" title="Java编程思想笔记七">6</a></span><span>7</span><span>8</span><span>9</span><span>10</span><span>11</span><span>12</span><span>13</span><span>14</span><span>15</span><span>16</span><span>17</span><span>18</span><span>19</span><span>20</span><span>21</span><span>22</span><span>23</span><span>24</span><span>25</span><span>26</span><span>27</span><span>28</span><span>29</span><span>30</span><span>31</span>';
        } else {
            for(var j=0;j<final_date;j++){        
                html+='<span id="d'+(j+1)+'">'+(j+1)+'</span>';
            }
        }
        //下个月的显示天数
        for(var k=0;k<surplus;k++){
            html+='<span class="g-calendar-grey">'+(k+1)+'</span>';
        }
        //fill
        this.oBody.innerHTML = html;
        // 当前状态
        if(year==this.c_year&&this.c_month==month){
            this.oBody.getElementsByTagName('span')[first_day+this.date-1].className='g-calendar-on';
        }

        // 对所有文章遍历,然后将有文章的日期加上链接,如果文章太多的话,生成页面会很大,去掉了
        
    },
    // next切换
    next:function(){
        var _that = this;
        this.oNext.onclick = function(){
            _that.month++;
            if(_that.month>11){
                _that.month = 0;
                _that.year++;
            }
            // 填充日历
            _that.fillDate(_that.year,_that.month);
        };
    },
    // back 切换
    back:function(){
        var _that = this;
        if(this.oBack != undefined) {
            this.oBack.onclick = function(){
                var postdate = new Date("Thu Nov 06 2014 11:02:46 GMT+0800"); 
                _that.year = postdate.getFullYear();
                _that.month = postdate.getMonth();
                // 填充日历
                _that.fillDate(_that.year,_that.month);
            };
        }
    },
    // now切换
    now:function(){
        var _that = this;
        if(this.oNow != undefined ) {
            this.oNow.onclick = function(){
                var nowDate = new Date(); 
                _that.year = nowDate.getFullYear();
                _that.month = nowDate.getMonth();
                // 填充日历
                _that.fillDate(_that.year,_that.month);
            };
        }
    },
    // prev切换
    prev:function(){
        var _that = this;
        this.oPrev.onclick = function(){
            _that.month--;
            if(_that.month<0){
                _that.month = 11;
                _that.year--;
            }
            // 填充日历
            _that.fillDate(_that.year,_that.month);
        };
    },
    init:function(){
        this.oTit.innerHTML = '<span>日</span><span>一</span><span>二</span><span>三</span><span>四</span><span>五</span><span>六</span>';
        // 获取今天的日历时间
        var now = new Date();
        this.c_year = this.year = now.getFullYear();
        this.c_month = this.month = now.getMonth();
        this.date = now.getDate();
        // 初始化--填充日历
        this.fillDate(this.year,this.month);
        //next切换
        this.next();
        //prev切换
        this.prev();
        //back 切换
        this.back();
        //now 切换
        this.now();
    }
}
new LGY_calendar('g-calendar');
</script>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Recent Posts</h3>
    <div class="widget">
      <ul>
        
          <li>
            <a href="/2015/09/01/javascript-summary/">JavaScript 总结</a>
          </li>
        
          <li>
            <a href="/2015/08/28/javascript-oop-function-expression-and-async/">JavaScript 面向对象程序设计、函数表达式和异步编程</a>
          </li>
        
          <li>
            <a href="/2015/08/28/javascript-reference-type/">JavaScript 引用类型</a>
          </li>
        
          <li>
            <a href="/2015/08/28/javascript-grammar/">JavaScript 基本语法</a>
          </li>
        
          <li>
            <a href="/2015/08/10/java-web/">Java Web 笔记</a>
          </li>
        
      </ul>
    </div>
  </div>


  
    
<div class="widget-wrap">
  <h3 class="widget-title">Recent Comments</h3>
  <ul class="widget ds-recent-comments" data-num-items="5" data-show-avatars="0" data-show-title="1" data-show-time="1"></ul>
</div>
<!-- 需要多说的公用代码 -->


  

</aside>

        
      </div>
      <footer id="footer">
  
  <div class="outer">
    <div id="footer-info" class="inner">
      &copy; 2015 howiefh<br>
      Powered by <a href="http://zespia.tw/hexo/" target="_blank">Hexo</a> and Theme by <a href="https://github.com/howiefh/hexo-theme-landscape-f" target="_blank" title="Landscape-F">Landscape-F</a>
    </div>
  </div>
</footer>

    </div>
    <nav id="mobile-nav">
  
    <a href="/" class="mobile-nav-link">Home</a>
  
    <a href="/archives" class="mobile-nav-link">Archives</a>
  
</nav>
    

<!-- 多说公共JS代码 start (一个网页只需插入一次) -->

<script type="text/javascript">
  var duoshuoQuery = {short_name:"howiefh"};
  (function() {
	var ds = document.createElement('script');
	ds.type = 'text/javascript';ds.async = true;
	ds.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') + '//static.duoshuo.com/embed.js';
	ds.charset = 'UTF-8';
	(document.getElementsByTagName('head')[0] 
		|| document.getElementsByTagName('body')[0]).appendChild(ds);
  })();
</script> 

<!-- 多说公共JS代码 end -->

<!-- 百度分享 start -->

<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":["mshare","douban","bdysc","sqq","qq","hi","baidu","huaban","youdao","sdo","mail","xg","diandian","fx","copy","print"],"bdPic":"","bdStyle":"1","bdSize":"16"},"share":{},"image":{"viewList":["qzone","tsina","tqq","renren","weixin"],"viewText":"分享到：","viewSize":"16"}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>

<!-- 百度分享 end -->

<!--
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<script src="/js/jquery.min.js"></script>
-->
<script src="/js/jquery.min.js" type="text/javascript"></script>


  <link rel="stylesheet" href="/fancybox/jquery.fancybox.css" type="text/css">
  <script src="/fancybox/jquery.fancybox.pack.js" type="text/javascript"></script>


<div class="bottom-btn">

	<a class="icon-gotop" href="javascript:void(0)" title="返回顶部"></a>
	<script src="/js/gotop.js" type="text/javascript"></script>
	<!--
	<script src="/js/gotop.js"></script>
	-->


	<a class="icon-toc-toggle" href="javascript:void(0)" title="文章目录"></a>
	<!--
	<script src="/js/toc_aside_toggle.js"></script>
	-->

</div>
<script src="/js/toc_aside_toggle.js" type="text/javascript"></script>


<script src="/js/script.js" type="text/javascript"></script>

  </div>
</body>
</html>
